package com.fzebu.fastboot.form.converter;

import com.fzebu.fastboot.annotations.Alias;
import com.fzebu.fastboot.form.exception.ConvertException;
import lombok.Getter;
import org.apache.commons.lang.StringUtils;
import weaver.conn.RecordSetTrans;
import weaver.soa.workflow.request.DetailTable;
import weaver.soa.workflow.request.Property;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Jack
 * @version 1.0.0
 * @create 2020/1/26 19:33
 */
public class FormConverter {

    private static final Map<Class<?>, Builder> BUILDER_MAP = new ConcurrentHashMap<>();

    private Builder builder;

    private FormConverter(Builder builder) {
        this.builder = builder;
    }

    public Object toJavaBean(ProcessHandler processHandler) throws ConvertException {
        this.checkBuilder(processHandler);
        return processHandler.toJavaBean();
    }

    public Object toJavaArray(ProcessHandler processHandler) throws ConvertException {
        this.checkBuilder(processHandler);
        return processHandler.toJavaArray();
    }

    private void checkBuilder(ProcessHandler processHandler) {
        if (this.builder == null) {
            throw new IllegalArgumentException("com.fzebu.fastboot.form.converter.FormConverter.Builder is null");
        }
        processHandler.initialize(this.builder);
    }

    public static Builder builder(Class<?> clazz) {
        Builder builder = BUILDER_MAP.get(clazz);
        if (builder == null) {
            builder = new Builder();
            builder.buildClass(clazz);
            BUILDER_MAP.put(clazz, builder);
        }
        return builder;
    }

    public static class Builder {

        @Getter
        private Class<?> clazz;

        @Getter
        private Property[] properties;

        @Getter
        private Map<String, List<String>> aliasFieldMap;

        @Getter
        private Map<String, Field> fieldMap;

        @Getter
        private DetailTable detailTable;

        @Getter
        private RecordSetTrans rst;

        private Builder() {}

        public Builder rst(RecordSetTrans rst) {
            this.rst = rst;
            return this;
        }

        public Builder setProperty(Property ... props) {
            this.properties = props;
            return this;
        }

        public Builder detailTable(DetailTable detailTable) {
            this.detailTable = detailTable;
            return this;
        }

        private void buildClass(Class<?> clazz) {
            Field[] fields = clazz.getDeclaredFields();
            int len = fields.length;
            this.aliasFieldMap = new HashMap<>(len);
            this.fieldMap = new HashMap<>(len);
            for (Field field : fields) {
                Alias annotation = field.getAnnotation(Alias.class);
                String fieldName = field.getName();
                String alias = (annotation != null && StringUtils.isNotEmpty(annotation.value()))
                        ? annotation.value() : fieldName;
                this.put(alias, fieldName);
                this.fieldMap.put(fieldName, field);
            }
            this.clazz = clazz;
        }

        private void put(String alias, String fileName) {
            List<String> list = this.aliasFieldMap.computeIfAbsent(alias,
                    k -> new ArrayList<>(1));
            list.add(fileName);
        }

        public FormConverter build() {
            if (this.clazz == null) {
                throw new IllegalArgumentException("class is null");
            }
            return new FormConverter(this);
        }
    }
}